package org.elephantt.webby.ibatis;

import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.event.RowHandler;

import java.sql.SQLException;
import java.util.Map;
import java.util.List;

/**
 * TODO: implement pluggable system to cover difference between DBs for cases where I want particular exceptions (e.g. unique constraint).
 */
public class IbatisClient {
  private SqlMapClient client;

  public SqlMapClient getClient() {
    return client;
  }

  public IbatisClient(SqlMapClient client) {
    this.client = client;
  }

  public Object insert(String s, Object o) {
    try {
      return client.insert(s, o);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public <T> T insert(String queryName, Class<T> returnClass, Map<String, Object> params) {
    return (T) insert(queryName, params);
  }


  public Object insert(String s) {
    try {
      return client.insert(s);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public int update(String s, Object o) {
    try {
      return client.update(s, o);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  private RuntimeException adaptException(SQLException e) {
    if (e.getSQLState() != null && e.getSQLState().equals("23505")) {
      return new UniqueConstraintException();
    } else {
      return new RuntimeException(e);
    }
  }

  public int update(String s) {
    try {
      return client.update(s);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public int delete(String s, Object o) {
    try {
      return client.delete(s, o);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public int delete(String s) {
    try {
      return client.delete(s);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public <T> T queryForObject(String queryName, Class<T> clazz, Map<String, Object> params) {
    return (T) queryForObject(queryName, params);
  }

  public <T> List<T> query(String queryName, Class<T> clazz, Map<String, Object> params) {
    return (List<T>) queryForList(queryName, params);
  }

  public <T> T queryForSingleObject(String queryName, Class<T> clazz, Map<String, Object> params) {
    return (T) queryForObject(queryName, params);
  }

  public Object queryForObject(String s, Object o) {
    try {
      return client.queryForObject(s, o);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public Object queryForObject(String s) {
    try {
      return client.queryForObject(s);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public <T> T queryForObject(String s, Class<T> clazz, Object param, Object value) {
    try {
      return (T) client.queryForObject(s, param, value);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public List queryForList(String s, Object o) {
    try {
      return client.queryForList(s, o);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public List queryForList(String s) {
    try {
      return client.queryForList(s);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public List queryForList(String s, Object o, int i, int i1) {
    try {
      return client.queryForList(s, o, i, i1);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public List queryForList(String s, int i, int i1) {
    try {
      return client.queryForList(s, i, i1);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public void queryWithRowHandler(String s, Object o, RowHandler rowHandler) {
    try {
      client.queryWithRowHandler(s, o, rowHandler);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public void queryWithRowHandler(String s, RowHandler rowHandler) {
    try {
      client.queryWithRowHandler(s, rowHandler);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public Map queryForMap(String s, Object o, String s1) {
    try {
      return client.queryForMap(s, o, s1);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }

  public Map queryForMap(String s, Object o, String s1, String s2) {
    try {
      return client.queryForMap(s, o, s1, s2);
    } catch (SQLException e) {
      throw adaptException(e);
    }
  }
}